package com.zyq.controller;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.zyq.exception.CustomException;
import com.zyq.exception.CustomUnauthorizedException;
import com.zyq.mapper.RoleMapper;
import com.zyq.mapper.UserMapper;
import com.zyq.model.common.BaseDto;
import com.zyq.model.common.Constant;
import com.zyq.model.common.ResponseBean;
import com.zyq.model.entity.HealthInformation;
import com.zyq.model.entity.Message;
import com.zyq.model.entity.RiskLevel;
import com.zyq.model.entity.User;
import com.zyq.model.request.RoleDto;
import com.zyq.model.request.UserDto;
import com.zyq.model.request.UserDto2;
import com.zyq.model.request.UserRequest;
import com.zyq.model.response.DoctorsResponse;
import com.zyq.model.response.UserResponse;
import com.zyq.model.response.UserStatusResponse;
import com.zyq.model.valid.group.UserEditValidGroup;
import com.zyq.model.valid.group.UserLoginValidGroup;
import com.zyq.service.IArticleService;
import com.zyq.service.IMessageService;
import com.zyq.service.IUserService;
import com.zyq.util.AesCipherUtil;
import com.zyq.util.JedisUtil;
import com.zyq.util.JwtUtil;
import com.zyq.util.UserUtil;
import com.zyq.util.common.StringUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.ibatis.annotations.Param;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.http.HttpStatus;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * UserController
 * @author dolyw.com
 * @date 2018/8/29 15:45
 */
@Api( tags = "用户接口")
@RestController
@RequestMapping("/user")
@PropertySource("classpath:config.properties")
public class UserController {

    /**
     * RefreshToken过期时间
     */
    @Value("${refreshTokenExpireTime}")
    private String refreshTokenExpireTime;

    private final UserUtil userUtil;

    private final IUserService userService;

    @Autowired
    private IMessageService messageService;

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private IArticleService articleService;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    public UserController(UserUtil userUtil, IUserService userService) {
        this.userUtil = userUtil;
        this.userService = userService;
    }

    /**
     * 获取用户列表
     * @param
     */
    @RequiresRoles("管理员")
    @ApiOperation("获取用户列表")
    @GetMapping
    public ResponseBean user(@Validated UserDto2 baseDto, @RequestHeader String Authorization) {
        if (baseDto.getPageNum() == null || baseDto.getPageSize() == null) {
            baseDto.setPageNum(1);
            baseDto.setPageSize(10);
        }
        PageHelper.startPage(baseDto.getPageNum(), baseDto.getPageSize());
        User user = new User().setAccount(baseDto.getAccount())
                .setRole(baseDto.getRole());
        List<UserStatusResponse> userDto11 = userMapper.selectUserByParam(user);
//        List<UserDto> userDto = new ArrayList<>();
//        BeanUtils.copyProperties(userDto11,userDto);
        PageInfo<UserStatusResponse> selectPage = new PageInfo<UserStatusResponse>(userDto11);
        if (userDto11 == null || userDto11.size() < 0) {
            throw new CustomException("查询失败(Query Failure)");
        }
        Map<String, Object> result = new HashMap<String, Object>(16);
        result.put("total", selectPage.getTotal());
        result.put("pages", selectPage.getPages());
//        result.put("data", selectPage.getList());
        List<UserStatusResponse> userStatusResponseList = new LinkedList<>();
        for(UserStatusResponse userDto1 : selectPage.getList()){
            UserStatusResponse userStatusResponse = new UserStatusResponse();
            userStatusResponse.setId(userDto1.getId());
            userStatusResponse.setEmail(userDto1.getEmail());
            userStatusResponse.setStatus(userDto1.getStatus());
            userStatusResponse.setBirth(userDto1.getBirth());
            userStatusResponse.setAccount(userDto1.getAccount());
            userStatusResponse.setAvatar(userDto1.getAvatar());
            userStatusResponse.setCountAttention(userDto1.getCountAttention());
            userStatusResponse.setCountFans(userDto1.getCountFans());
            userStatusResponse.setIntroduction(userDto1.getIntroduction());
            userStatusResponse.setProof(userDto1.getProof());
            userStatusResponse.setRole(userDto1.getRole());
            userStatusResponse.setRegTime(userDto1.getRegTime());
            userStatusResponse.setSex(userDto1.getSex());
            userStatusResponse.setUsername(userDto1.getUsername());
            userStatusResponse.setTelephoneNumber(userDto1.getTelephoneNumber());
            if(userDto1.getStatus() == 0) {
                userStatusResponse.setStatusDetail("未审核");
            }else if(userDto1.getStatus() == 1 ){
                userStatusResponse.setStatusDetail("审核通过");
            }else{
                userStatusResponse.setStatusDetail("审核未通过");
            }
            userStatusResponseList.add(userStatusResponse);
        }
        result.put("data", userStatusResponseList);
        return new ResponseBean(HttpStatus.OK.value(), "查询成功(Query was successful)", result);
    }

    /**
     * 获取当前登录用户信息
     * @param
     */
    @ApiOperation("获取当前登录用户信息")
    @GetMapping("/info")
    @RequiresAuthentication
    public ResponseBean info(@RequestHeader String Authorization) {

        UserResponse userResponse = new UserResponse();

        userResponse.setBasicUserInformation(userService.selectById(userUtil.getUserId().intValue()));
                userService.getUserAll(userResponse);
        return new ResponseBean(HttpStatus.OK.value(), "成功获取当前登录用户信息", userResponse);
    }

    /**
     * 获取指定用户
     * @param id
     */
    @ApiOperation("获取指定用户")
    @GetMapping("/{id}")
    public ResponseBean findById(@PathVariable("id") Long id) {

        UserResponse userResponse = new UserResponse();
        userResponse.setBasicUserInformation(userService.selectById(id.intValue()));
        userService.getUserAll(userResponse);
        return new ResponseBean(HttpStatus.OK.value(), "成功获取当前登录用户信息", userResponse);
    }

    /**
     * 修改密码
     */
    @ApiOperation("修改密码")
    @GetMapping("/updatePassword")
//    @RequiresPermissions("user:edit")
    public ResponseBean updatePassword(@RequestParam("password") String password, @RequestHeader String Authorization) {
        // 查询数据库密码
        UserDto userDto = new UserDto();
        userDto.setPassword(password);
        userDto.setAccount(userUtil.getAccount());
        UserDto userDtoTemp = new UserDto();
        userDtoTemp.setAccount(userDto.getAccount());
        userDtoTemp = userService.selectOne(userDtoTemp);
        if (userDtoTemp == null) {
            throw new CustomUnauthorizedException("该帐号不存在(Account not exist.)");
        } else {
            userDto.setId(userDtoTemp.getId());
        }
        // FIXME: 如果不一样就说明用户修改了密码，重新加密密码(这个处理不太好，但是没有想到好的处理方式)
        if (!userDtoTemp.getPassword().equals(userDto.getPassword())) {
            // 密码以帐号+密码的形式进行AES加密
            if (userDto.getPassword().length() > Constant.PASSWORD_MAX_LEN) {
                throw new CustomException("密码最多8位(Password up to 8 bits.)");
            }
            String key = AesCipherUtil.enCrypto(userDto.getAccount() + userDto.getPassword());
            userDto.setPassword(key);
        }
        int count = userService.updateByPrimaryKeySelective(userDto);
        if (count <= 0) {
            throw new CustomException("更新失败(Update Failure)");
        }
        return new ResponseBean(HttpStatus.OK.value(), "更新成功(Update Success)", userDto);
    }


    /**
     * 更新用户
     */
    @ApiOperation("更新用户基本信息")
    @PutMapping
//    @RequiresPermissions("user:edit")
    public ResponseBean update(@Validated(UserEditValidGroup.class)@RequestBody UserDto userDto,@RequestHeader String Authorization) {
        // 查询数据库密码
        UserDto userDtoTemp = new UserDto();
        userDtoTemp.setAccount(userDto.getAccount());
        userDtoTemp = userService.selectOne(userDtoTemp);
        if (userDtoTemp == null) {
            throw new CustomUnauthorizedException("该帐号不存在(Account not exist.)");
        } else {
            userDto.setId(userDtoTemp.getId());
        }
        // FIXME: 如果不一样就说明用户修改了密码，重新加密密码(这个处理不太好，但是没有想到好的处理方式)
        if (userDto.getPassword()!=null && !userDtoTemp.getPassword().equals(userDto.getPassword())) {
            // 密码以帐号+密码的形式进行AES加密
            if (userDto.getPassword().length() > Constant.PASSWORD_MAX_LEN) {
                throw new CustomException("密码最多8位(Password up to 8 bits.)");
            }
            String key = AesCipherUtil.enCrypto(userDto.getAccount() + userDto.getPassword());
            userDto.setPassword(key);
        }
        int count = userService.updateByPrimaryKeySelective(userDto);
        if (count <= 0) {
            throw new CustomException("更新失败(Update Failure)");
        }
        return new ResponseBean(HttpStatus.OK.value(), "更新成功(Update Success)", userDto);
    }

    /**
     * 删除用户（注销账户）
     * @param id
     */
    @ApiOperation("删除用户")
    @DeleteMapping("/{id}")
    @RequiresRoles(value = "管理员")
    public ResponseBean delete(@PathVariable("id") Long id ,@RequestHeader String Authorization ) {
        int count = userService.deleteByPrimaryKey(id);
        if (count <= 0) {
            throw new CustomException("删除失败，ID不存在(Deletion Failed. ID does not exist.)");
        }
        return new ResponseBean(HttpStatus.OK.value(), "删除成功(Delete Success)", null);
    }

    /**
     * 用户点赞文章
     * @param articleId
     * @return
     */
    @ApiOperation("用户点赞文章")
    @RequestMapping(value = "/getLike", method = RequestMethod.GET)
    public ResponseBean getLike(@RequestParam String articleId, @RequestHeader String Authorization){
        String userId = userUtil.getUserId().toString();
        Message message = new Message()
                .setUserId(articleService.selectArticleById(Long.valueOf(articleId)).getUserId())
                .setAId(Long.valueOf(userId))
                .setBId(Long.valueOf(articleId))
                .setDetail("点赞");
        messageService.insertMessage(message);
        userService.insertGetLike(userId,articleId);
        return new ResponseBean(HttpStatus.OK.value(), "操作成功", null);
    }

    /**
     * 用户取消点赞文章
     * @param articleId
     * @return
     */
    @ApiOperation("用户取消点赞文章")
    @RequestMapping(value = "/deleteGetLike", method = RequestMethod.GET)
    public ResponseBean deleteGetLike(@RequestParam String articleId, @RequestHeader String Authorization){
        String userId = userUtil.getUserId().toString();
        userService.deleteGetLike(userId,articleId);
        return new ResponseBean(HttpStatus.OK.value(), "操作成功", null);
    }

    /**
     * 用户收藏文章
     * @param articleId
     * @return
     */
    @ApiOperation("用户收藏文章")
    @RequestMapping(value = "/collectArticle", method = RequestMethod.GET)
    public ResponseBean collectArticle(@RequestParam String articleId, @RequestHeader String Authorization){
        String userId = userUtil.getUserId().toString();
        Message message = new Message()
                .setUserId(articleService.selectArticleById(Long.valueOf(articleId)).getUserId())
                .setAId(Long.valueOf(userId))
                .setBId(Long.valueOf(articleId))
                .setDetail("收藏");
        messageService.insertMessage(message);
        userService.collectArticle(userId,articleId);
        return new ResponseBean(HttpStatus.OK.value(), "操作成功", null);
    }

    /**
     * 用户取消收藏
     * @param articleId
     * @return
     */
    @ApiOperation("用户取消收藏")
    @RequestMapping(value = "/cancelCollectionArticle", method = RequestMethod.GET)
    public ResponseBean cancelCollectionArticle(@RequestParam String articleId, @RequestHeader String Authorization){
        String userId = userUtil.getUserId().toString();
        userService.cancelCollectionArticle(userId,articleId);
        return new ResponseBean(HttpStatus.OK.value(), "操作成功", null);
    }

    /**
     * 判断是否关注
     */
    @ApiOperation("判断是否关注")

    @RequestMapping(value = "/flagAttention", method = RequestMethod.GET)
    public ResponseBean flagAttention(@RequestParam Long attentionId){
        Subject subject = SecurityUtils.getSubject();
        // 登录了返回true
        if (subject.isAuthenticated()) {
            if(userService.flagAttention(userUtil.getUserId(),attentionId)>0)
                return new ResponseBean(HttpStatus.OK.value(), "您已经登录了(You are already logged in)", true);
            else {
                return new ResponseBean(HttpStatus.OK.value(), "您已经登录了(You are already logged in)", false);
            }
        } else {
            return new ResponseBean(HttpStatus.OK.value(), "你是游客(You are guest)", null);
        }
    }

    /**
     * 关注
     * @param attentionId
     * @return
     */
    @RequiresAuthentication
    @ApiOperation("关注")
    @RequestMapping(value = "/insertAttention", method = RequestMethod.GET)
    public ResponseBean insertAttention(@RequestParam String attentionId){
        String userId = userUtil.getUserId().toString();
        userService.insertAttention(userId,attentionId);
        Message message = new Message()
                .setUserId(Long.valueOf(attentionId))
                .setAId(Long.valueOf(userId))
                .setDetail("关注");
        messageService.insertMessage(message);
        return new ResponseBean(HttpStatus.OK.value(), "操作成功", null);
    }

    /**
     * 取关
     * @param attentionId
     * @return
     */
    @RequiresAuthentication
    @ApiOperation("取关")
    @RequestMapping(value = "/cancelAttention", method = RequestMethod.GET)
    public ResponseBean deleteAttention(@RequestParam String attentionId){
        String userId = userUtil.getUserId().toString();
        userService.deleteAttention(userId,attentionId);
        return new ResponseBean(HttpStatus.OK.value(), "操作成功", null);
    }

    /**
     * 用户通过健康测评更新健康信息表
     * @param score
     * @return
     */
    @ApiOperation("用户通过健康测评更新健康信息表")
    @PostMapping("/updateHealthAssessmentByUser")
    public ResponseBean updateHealthAssessmentByUser(long score,@RequestHeader String Authorization){
        RiskLevel riskLevel = userService.updateHealthAssessmentByUser(score,userUtil.getUser());
        if(riskLevel == null ) {
            return new ResponseBean(HttpStatus.OK.value(), "分数不合规，向管理员申请查看具体原因", null);
        }
        Map<String,String> map = new HashMap<>();
        map.put("tips",riskLevel.getTips());
            return new ResponseBean(HttpStatus.OK.value(), "更新成功", map);
    }

    /**
     * 推荐医生
     * @param page
     * @return
     */
    @ApiOperation("推荐医生")
    @GetMapping("/getDoctors")
    public ResponseBean recommendDoctors(@RequestParam Long page){

        PageHelper.startPage(page.intValue(),2);
        List<DoctorsResponse> list = userService.recommendDoctors(page.intValue());
        PageInfo<DoctorsResponse> selectPage = new PageInfo<>(list);
        Map<String,Object> result = new HashMap<>();
        result.put("total", selectPage.getTotal());
        result.put("pages", selectPage.getPages());
        result.put("data", selectPage.getList());
        return new ResponseBean(HttpStatus.OK.value(), "操作成功", result);
    }


























    /**
     * 用户注册
     * @param userDto
     *
     * @return java.util.Map<java.lang.String,java.lang.Object>
     */
    @ApiOperation("用户注册")
    @PostMapping("/register")
    public ResponseBean add(@RequestBody UserRequest userDto){
        // 判断当前帐号是否存在
        UserDto userDtoTemp = new UserDto();
        userDto.setAccount(userDto.getTelephoneNumber());//账号等于电话号码
        userDtoTemp.setAccount(userDto.getAccount());
        userDtoTemp = userService.selectOne(userDtoTemp);
        // 检查账号名
        if (userDtoTemp != null && StringUtil.isNotBlank(userDtoTemp.getPassword())) {
            return new ResponseBean(403, "该帐号已存在",null);
        }
        userDtoTemp = new UserDto();
        userDtoTemp.setEmail(userDto.getEmail());
        userDtoTemp = userService.selectOne(userDtoTemp);
        // 检查邮箱号
        if (userDtoTemp!= null && userDtoTemp.getStatus()!=0) {
            return new ResponseBean(403, "该邮箱已被注册",null);
        }
        userDto.setRegTime(new Date());
        // 密码以帐号+密码的形式进行AES加密
        if (userDto.getPassword().length() > Constant.PASSWORD_MAX_LEN) {
            return new ResponseBean(403, "密码最多8位(Password up to 8 bits.)",null);
        }
        String key = AesCipherUtil.enCrypto(userDto.getAccount() + userDto.getPassword());
        userDto.setPassword(key);
        userDto.setUsername(RandomStringUtils.randomAlphanumeric(10));
        String role = userDto.getRole();
        if(role.equals("医生") || role.equals("糖尿病患者")) {
            userDto.setStatus(0L);
            if (role.equals("医生")) {
                userDto.setAvatar("http://localhost:8888/static/doctor.png");
            }else {
                userDto.setAvatar("http://localhost:8888/static/patient.png");
            }
            if(userService.insertUser(userDto)>0){
                if (role.equals("医生")){
                    userService.insertUserRole(userDto.getId(),2L);
                }else{
                    userService.insertUserRole(userDto.getId(),3L);
                }
                return new ResponseBean(HttpStatus.OK.value(), "待管理员审核，24小时内将发送审核结果到您的邮箱", userDto);
            }
            else{
                return new ResponseBean(403, "注册失败(Insert Failure)",null);
            }
        }
        else {
            userDto.setAccount(userDto.getTelephoneNumber())
                    .setAvatar("http://localhost:8888/static/people.png");
            if (userService.insertUser(userDto) <= 0) {
                return new ResponseBean(403, "注册失败(Insert Failure)",null);
            }
            userService.insertUserRole(userDto.getId(),4L);
            return new ResponseBean(HttpStatus.OK.value(), "注册成功(Insert Success)", userDto);
        }
    }

    /**
     * 登录授权
     * @param userDto
     * @return com.zyq.model.common.ResponseBean
     */
    @ApiOperation("用户登录授权")
    @PostMapping("/login")
    public ResponseBean login(@Validated(UserLoginValidGroup.class) @RequestBody UserDto userDto, HttpServletResponse httpServletResponse) {
        // 查询数据库中的帐号信息
        UserDto userDtoTemp = new UserDto();
        userDtoTemp.setAccount(userDto.getAccount());
        userDtoTemp = userService.selectOne(userDtoTemp);
        if (userDtoTemp == null) {
            return new ResponseBean(403, "该帐号不存在(The account does not exist.)",null);
        }
        if(userDtoTemp.getStatus() == 0){
            return new ResponseBean(403, "注册账号未审核,请耐心等待，注册结果会在24小时发至锁定的邮箱",null);
        }
        else if(userDtoTemp.getStatus() == 2) {
            return new ResponseBean(403, "您注册的账号审核未通过，请重新提供确切的用户凭证信息证实您的身份，再次注册",null);
        }
        // 密码进行AES解密
        String key = AesCipherUtil.deCrypto(userDtoTemp.getPassword());
        // 因为密码加密是以帐号+密码的形式进行加密的，所以解密后的对比是帐号+密码
        if (key.equals(userDto.getAccount() + userDto.getPassword())) {
            // 清除可能存在的Shiro权限信息缓存
            if (JedisUtil.exists(Constant.PREFIX_SHIRO_CACHE + userDto.getAccount())) {
                JedisUtil.delKey(Constant.PREFIX_SHIRO_CACHE + userDto.getAccount());
            }
            // 设置RefreshToken，时间戳为当前时间戳，直接设置即可(不用先删后设，会覆盖已有的RefreshToken)
            String currentTimeMillis = String.valueOf(System.currentTimeMillis());
            JedisUtil.setObject(Constant.PREFIX_SHIRO_REFRESH_TOKEN + userDto.getAccount(), currentTimeMillis, Integer.parseInt(refreshTokenExpireTime));
            // 从Header中Authorization返回AccessToken，时间戳为当前时间戳
            String token = JwtUtil.sign(userDto.getAccount(), currentTimeMillis);
            httpServletResponse.setHeader("Authorization", token);
            httpServletResponse.setHeader("Access-Control-Expose-Headers", "Authorization");
            Map<String,Object> map = new HashMap<>();
            map.put("Authorization", token);
            return new ResponseBean(HttpStatus.OK.value(), "登录成功(Login Success.)",map );
        } else {
            throw new CustomUnauthorizedException("帐号或密码错误(Account or Password Error.)");
        }
    }

    /**
     * 测试登录
     * @param
     */
    @ApiOperation("测试登录")
    @GetMapping("/article")
    public ResponseBean article() {
        Subject subject = SecurityUtils.getSubject();
        // 登录了返回true
        if (subject.isAuthenticated()) {
            return new ResponseBean(HttpStatus.OK.value(), "您已经登录了(You are already logged in)", null);
        } else {
            return new ResponseBean(HttpStatus.OK.value(), "你是游客(You are guest)", null);
        }
    }

    /**
     * 退出登陆
     * @param id
     */
    @ApiOperation("退出登陆")
    @DeleteMapping("/loginOut/{id}")
//    @RequiresPermissions(logical = Logical.AND, value = {"user:edit"})
    public ResponseBean deleteOnline(@PathVariable("id") Integer id) {
        UserDto userDto = userService.selectById(id);
        if (JedisUtil.exists(Constant.PREFIX_SHIRO_REFRESH_TOKEN + userDto.getAccount())) {
            if (JedisUtil.delKey(Constant.PREFIX_SHIRO_REFRESH_TOKEN + userDto.getAccount()) > 0) {
                return new ResponseBean(HttpStatus.OK.value(), "操作成功", null);
            }
        }
        throw new CustomException("失败，Account不存在( Failed. Account does not exist.)");
    }

    /**
     * 测试登录注解(@RequiresAuthentication和subject.isAuthenticated()返回true一个性质)
     */
//    @GetMapping("/article2")
//    @RequiresAuthentication
//    @ApiOperation("测试登录注解")
//    public ResponseBean requireAuth() {
//        return new ResponseBean(HttpStatus.OK.value(), "您已经登录了(You are already logged in)", null);
//    }

    /**
     * 获取在线用户(查询Redis中的RefreshToken)
     */
//    @ApiOperation("获取在线用户")
//    @GetMapping("/online")
//    @RequiresPermissions(logical = Logical.AND, value = {"user:view"})
//    public ResponseBean online() {
//        List<Object> userDtos = new ArrayList<Object>();
//        // 查询所有Redis键
//        Set<String> keys = JedisUtil.keysS(Constant.PREFIX_SHIRO_REFRESH_TOKEN + "*");
//        for (String key : keys) {
//            if (JedisUtil.exists(key)) {
//                // 根据:分割key，获取最后一个字符(帐号)
//                String[] strArray = key.split(":");
//                UserDto userDto = new UserDto();
//                userDto.setAccount(strArray[strArray.length - 1]);
//                userDto = userService.selectOne(userDto);
//                // 设置登录时间
//                userDto.setLoginTime(new Date(Long.parseLong(JedisUtil.getObject(key).toString())));
//                userDtos.add(userDto);
//            }
//        }
//        if (userDtos == null || userDtos.size() < 0) {
//            throw new CustomException("查询失败(Query Failure)");
//        }
//        return new ResponseBean(HttpStatus.OK.value(), "查询成功(Query was successful)", userDtos);
//    }

}
